Passed
Push — master ( 083542...d344b9 )
by EMP
01:15
created

main.js ➔ addAccountToTable   B

Complexity

Conditions 6

Size

Total Lines 26
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 20
dl 0
loc 26
rs 8.4666
c 0
b 0
f 0
cc 6
1
"use strict";
2
3
sodium.ready.then(function() {
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
4
5
const ae = new AllEars(function(ok) {
1 ignored issue
show
Bug introduced by
The variable AllEars seems to be never declared. If this is a global, consider adding a /** global: AllEars */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
6
	if (ok) {
7
		document.getElementById("txt_skey").style.background = "#466";
8
		document.getElementById("txt_skey").maxLength = "64";
9
	} else {
10
		console.log("Failed to load All-Ears");
11
	}
12
});
13
14
function TabState(cur, max, btnDele, btnUpdt) {
15
	this.cur = cur;
16
	this.max = max;
17
	this.btnDele = btnDele;
18
	this.btnUpdt = btnUpdt;
19
}
20
21
const tabs = [
22
	new TabState(0, 0, false, true), // Inbox
23
	new TabState(0, 0, false, true), // Outbx
24
	new TabState(0, 2, true, false), // Write
25
	new TabState(0, 2, false, false), // Notes
26
	new TabState(0, 3, false, true) // Tools
27
];
28
29
let showHeaders = false;
30
31
let tab = 0;
32
const TAB_INBOX = 0;
33
const TAB_OUTBX = 1;
0 ignored issues
show
Unused Code introduced by
The constant TAB_OUTBX seems to be never used. Consider removing it.
Loading history...
34
const TAB_WRITE = 2;
35
const TAB_NOTES = 3;
36
const TAB_TOOLS = 4;
37
38
// Helper functions
39
function getCountryName(countryCode) {
40
	const opts = document.getElementById("gatekeeper_country");
41
42
	for (let i = 0; i < opts.length; i++) {
43
		if (opts[i].value === countryCode) {
44
			return opts[i].textContent;
45
		}
46
	}
47
48
	return "Unknown countrycode: " + countryCode;
49
}
50
51
function getCountryFlag(countryCode) {
52
	return sodium.to_string(new Uint8Array([
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
53
		240, 159, 135, 166 + countryCode.codePointAt(0) - 65,
54
		240, 159, 135, 166 + countryCode.codePointAt(1) - 65
55
	]));
56
}
57
58
function getMsgId(num) {
59
	let i;
60
	if (ae.GetExtMsgHeaders(num).toLowerCase().slice(0, 11) === "message-id:") {
61
		i = 0;
62
	} else {
63
		i = ae.GetExtMsgHeaders(num).toLowerCase().indexOf("\nmessage-id:");
64
		if (i < 1) return "ERR";
65
		i++;
66
	}
67
68
	const x = ae.GetExtMsgHeaders(num).slice(i + 11).trim();
69
	if (x[0] !== "<") return "ERR2";
70
	return x.slice(1, x.indexOf(">"));
71
}
72
73
function clearDisplay() {
74
	let el = document.getElementById("midright").getElementsByTagName("img");
75
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("audio");
76
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("video");
77
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("embed");
78
	if (el.length !== 1) return;
79
80
	URL.revokeObjectURL(el[0].src);
1 ignored issue
show
Bug introduced by
The variable URL seems to be never declared. If this is a global, consider adding a /** global: URL */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
81
	el[0].remove();
82
}
83
84
function displayFile(num) {
85
	clearDisplay();
86
87
	document.getElementById("midright").scroll(0, 0);
88
	document.getElementById("btn_reply").disabled = true;
89
	document.getElementById("btn_mdele").disabled = true;
90
91
	document.getElementById("midright").children[0].hidden = true;
92
	document.getElementById("midright").children[1].textContent = ae.GetUplMsgTitle(num);
93
94
	switch (ae.GetUplMsgType(num)) {
95
		case "text": {
96
			document.getElementById("midright").children[2].hidden = false;
97
			document.getElementById("midright").children[2].textContent = sodium.to_string(ae.GetUplMsgBody(num));
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
98
		break;}
99
100
		case "image": {
101
			document.getElementById("midright").children[2].hidden = true;
102
			const img = document.createElement("img");
103
			img.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
2 ignored issues
show
Bug introduced by
The variable Blob seems to be never declared. If this is a global, consider adding a /** global: Blob */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable URL seems to be never declared. If this is a global, consider adding a /** global: URL */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
104
			document.getElementById("midright").appendChild(img);
105
106
			img.onclick = function() {
107
				if (!document.fullscreen)
108
					img.requestFullscreen();
109
				else
110
					document.exitFullscreen();
111
			};
112
		break;}
113
114
		case "audio": {
115
			document.getElementById("midright").children[2].hidden = true;
116
			const el = document.createElement("audio");
117
			el.controls = "controls";
118
			el.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
119
			document.getElementById("midright").appendChild(el);
120
		break;}
121
122
		case "video": {
123
			document.getElementById("midright").children[2].hidden = true;
124
			const el = document.createElement("video");
125
			el.controls = "controls";
126
			el.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
127
			document.getElementById("midright").appendChild(el);
128
		break;}
129
130
		case "pdf": {
131
			document.getElementById("midright").children[2].hidden = true;
132
			const el = document.createElement("embed");
133
			el.type = "application/pdf";
134
			el.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
135
			document.getElementById("midright").appendChild(el);
136
		break;}
137
	}
138
}
139
140
function displayMsg(isInt, num) {
141
	clearDisplay();
142
143
	document.getElementById("midright").scroll(0, 0);
144
145
	const ts = isInt? ae.GetIntMsgTime(num) : ae.GetExtMsgTime(num);
146
147
	document.getElementById("btn_reply").disabled = false;
148
	document.getElementById("btn_reply").onclick = function() {
149
		document.getElementById("write_recv").value = isInt? ae.GetIntMsgFrom(num) : ae.GetExtMsgFrom(num);
150
		document.getElementById("write_subj").value = "Re: " + (isInt ? ae.GetIntMsgTitle(num) : ae.GetExtMsgTitle(num));
151
		document.getElementById("write_rply").textContent = (isInt? "" : getMsgId(num));
152
		document.getElementById("btn_write").click();
153
		document.getElementById("div_write_1").hidden = false;
154
		document.getElementById("div_write_2").hidden = true;
155
		document.getElementById("write_body").focus();
156
		for (const opt of document.getElementById("write_from").options) {
157
			if (opt.value === (isInt ? ae.GetIntMsgTo(num) : ae.GetExtMsgTo(num))) {
158
				opt.selected = true;
159
			}
160
		}
161
	};
162
163
	document.getElementById("btn_mdele").disabled = false;
164
	document.getElementById("btn_mdele").onclick = function() {
165
		this.blur();
166
167
		ae.Message_Delete(isInt? ae.GetIntMsgIdHex(num) : ae.GetExtMsgIdHex(num), function(success) {
168
			if (!success) console.log("Failed delete");
169
		});
170
	};
171
172
	document.getElementById("midright").children[0].hidden = false;
173
	document.getElementById("midright").children[2].hidden = false;
174
175
	if (isInt) {
176
		document.getElementById("midright").children[1].textContent = ae.GetIntMsgTitle(num);
177
		document.getElementById("midright").children[2].textContent = ae.GetIntMsgBody(num);
178
	} else {
179
		document.getElementById("midright").children[2].innerHTML = "";
180
181
		const headers = document.createElement("p");
182
		headers.textContent = ae.GetExtMsgHeaders(num);
183
		headers.className = "mono";
184
		headers.hidden = !showHeaders;
185
		document.getElementById("midright").children[2].appendChild(headers);
186
187
		const body = document.createElement("p");
188
		body.textContent = ae.GetExtMsgBody(num);
189
		document.getElementById("midright").children[2].appendChild(body);
190
191
		document.getElementById("midright").children[1].textContent = ae.GetExtMsgTitle(num);
192
		document.getElementById("midright").children[1].onclick = function() {showHeaders = !showHeaders; headers.hidden = !showHeaders;};
193
		document.getElementById("midright").children[1].style.cursor = "pointer";
194
	}
195
196
	document.getElementById("readmsg_to").textContent = isInt ? ae.GetIntMsgTo(num) : ae.GetExtMsgTo(num);
197
	document.getElementById("readmsg_date").children[0].textContent = new Date(ts * 1000).toISOString().slice(0, 19).replace("T", " ");
198
199
	if (!isInt) {
200
		document.getElementById("readmsg_ip").hidden = false;
201
		document.getElementById("readmsg_country").hidden = false;
202
		document.getElementById("readmsg_tls").hidden = false;
203
		document.getElementById("readmsg_greet").hidden = false;
204
		document.getElementById("readmsg_timing").hidden = false;
205
		document.getElementById("readmsg_envfrom").hidden = false;
206
207
		const cc = ae.GetExtMsgCountry(num);
208
209
		document.getElementById("readmsg_ip").children[0].textContent = ae.GetExtMsgIp(num);
210
		document.getElementById("readmsg_country").textContent = getCountryFlag(cc) + " " + getCountryName(cc);
211
		document.getElementById("readmsg_tls").children[0].textContent = ae.GetExtMsgTLS(num);
212
		document.getElementById("readmsg_greet").children[0].textContent = ae.GetExtMsgGreet(num);
213
		document.getElementById("readmsg_envfrom").textContent = ae.GetExtMsgFrom(num);
214
215
		let flagText = "";
216
		if (!ae.GetExtMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
217
		if (!ae.GetExtMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
218
		if (!ae.GetExtMsgFlagPExt(num)) flagText += "<abbr title=\"The sender did not use the Extended (ESMTP) protocol\">SMTP</abbr> ";
219
		if (!ae.GetExtMsgFlagQuit(num)) flagText += "<abbr title=\"The sender did not issue the required QUIT command\">QUIT</abbr> ";
220
		if (ae.GetExtMsgFlagRare(num)) flagText += "<abbr title=\"The sender issued unusual command(s)\">RARE</abbr> ";
221
		if (ae.GetExtMsgFlagFail(num)) flagText += "<abbr title=\"The sender issued invalid command(s)\">FAIL</abbr> ";
222
		if (ae.GetExtMsgFlagPErr(num)) flagText += "<abbr title=\"The sender violated the protocol\">PROT</abbr> ";
223
		document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
224
	} else {
225
		document.getElementById("readmsg_ip").hidden = true;
226
		document.getElementById("readmsg_country").hidden = true;
227
		document.getElementById("readmsg_tls").hidden = true;
228
		document.getElementById("readmsg_greet").hidden = true;
229
		document.getElementById("readmsg_timing").hidden = true;
230
		document.getElementById("readmsg_envfrom").hidden = true;
231
232
		let symbol = "<span title=\"Invalid level\">&#x26a0;</span>";
233
		if (ae.GetIntMsgFrom(num) === "system") {if (ae.GetIntMsgLevel(num) === 3) symbol = "<span title=\"System\">&#x1f162;</span>";} // S (System)
234
		else if (ae.GetIntMsgLevel(num) === 0) symbol = "<span title=\"Level 0 User\">&#x1f10c;</span>"; // 0
235
		else if (ae.GetIntMsgLevel(num) === 1) symbol = "<span title=\"Level 1 User\">&#x278a;</span>"; // 1
236
		else if (ae.GetIntMsgLevel(num) === 2) symbol = "<span title=\"Level 2 User\">&#x278b;</span>"; // 2
237
		else if (ae.GetIntMsgLevel(num) === 3) symbol = "<span title=\"Administrator\">&#x1f150;</span>"; // A (Admin)
238
		document.getElementById("readmsg_from").innerHTML = symbol + " " + ae.GetIntMsgFrom(num);
239
240
		let flagText = "";
241
		if (!ae.GetIntMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
242
		if (!ae.GetIntMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
243
		document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
244
	}
245
}
246
247
// Interface
248
function addMsg(isInt, i) {
249
	const row = document.getElementById("tbl_inbox").insertRow(-1);
250
	const cellTime = row.insertCell(-1);
251
	const cellSubj = row.insertCell(-1);
252
	const cellSnd1 = row.insertCell(-1);
253
	const cellSnd2 = row.insertCell(-1);
254
255
	const ts = isInt? ae.GetIntMsgTime(i) : ae.GetExtMsgTime(i);
256
	cellTime.setAttribute("data-ts", ts);
257
	cellTime.textContent = new Date(ts * 1000).toISOString().slice(0, 10);
258
259
	cellSubj.textContent = isInt? ae.GetIntMsgTitle(i) : ae.GetExtMsgTitle(i);
260
261
	if (isInt) {
262
		cellSnd1.textContent = ae.GetIntMsgFrom(i);
263
		cellSnd1.className = (ae.GetIntMsgFrom(i).length === 16) ? "mono" : "";
264
	} else {
265
		const from1 = ae.GetExtMsgFrom(i);
266
		const from2 = from1.substring(from1.indexOf("@") + 1);
267
		const cc = ae.GetExtMsgCountry(i);
268
269
		cellSnd1.textContent = from1.substring(0, from1.indexOf("@"));
270
271
		const flag = document.createElement("abbr");
272
		flag.textContent = getCountryFlag(cc);
273
		flag.title = getCountryName(cc);
274
		cellSnd2.appendChild(flag);
275
276
		const fromText = document.createElement("span");
277
		fromText.textContent = " " + from2;
278
		cellSnd2.appendChild(fromText);
279
	}
280
281
	row.onclick = function() {
282
		displayMsg(isInt, i);
283
	};
284
}
285
286
function getRowsPerPage() {
287
	const tbl = document.getElementById("tbl_inbox");
288
	tbl.innerHTML = "";
289
	const row = tbl.insertRow(-1);
290
	const cell = row.insertCell(-1);
291
	cell.textContent = "0";
292
293
	const rowsPerPage = Math.floor(getComputedStyle(document.getElementById("div_inbox")).height.replace("px", "") / getComputedStyle(document.querySelector("#tbl_inbox > tbody > tr:first-child")).height.replace("px", "")) - 1; // -1 allows space for 'load more'
294
	tbl.innerHTML = "";
295
	return rowsPerPage;
296
}
297
298
function addMessages() {
299
	const rowsPerPage = getRowsPerPage();
300
	let skipMsgs = rowsPerPage * tabs[TAB_INBOX].cur;
301
302
	const maxExt = ae.GetExtMsgCount();
303
	const maxInt = ae.GetIntMsgCount();
304
305
	tabs[TAB_INBOX].max = Math.floor((maxExt + maxInt) / rowsPerPage);
306
307
	let numExt = 0;
308
	let numInt = 0;
309
	let numAdd = 0;
310
311
	while (numAdd < rowsPerPage) {
312
		const tsInt = (numInt < maxInt) ? ae.GetIntMsgTime(numInt) : -1;
313
		const tsExt = (numExt < maxExt) ? ae.GetExtMsgTime(numExt) : -1;
314
		if (tsInt === -1 && tsExt === -1) break;
315
316
		if (tsInt !== -1 && (tsExt === -1 || tsInt > tsExt)) {
317
			if (skipMsgs > 0) skipMsgs--; else {addMsg(true, numInt); numAdd++;}
318
			numInt++;
319
		} else if (tsExt !== -1) {
320
			if (skipMsgs > 0) skipMsgs--; else {addMsg(false, numExt); numAdd++;}
321
			numExt++;
322
		}
323
	}
324
325
	if (ae.GetReadyMsgBytes() < ae.GetTotalMsgBytes()) {
326
		const inbox = document.getElementById("tbl_inbox");
327
		const row = inbox.insertRow(-1);
328
		const cell = row.insertCell(-1);
329
		cell.textContent = "Load more (" + (ae.GetTotalMsgBytes() - ae.GetReadyMsgBytes()) / 1024 + " KiB left)";
330
331
		row.onclick = function() {
332
			this.onclick = "";
333
334
			ae.Message_Browse(false, function(successBrowse) {
335
				document.getElementById("tbl_inbox").style.opacity = 1;
336
337
				if (successBrowse) {
338
					addMessages();
339
					addUploads();
340
					if (tabs[tab].cur < tabs[tab].max) document.getElementById("btn_rght").disabled = false;
341
				}
342
			});
343
		};
344
	}
345
}
346
347
function addUploads() {
348
	const tbl = document.getElementById("tbd_uploads");
349
	tbl.innerHTML = "";
350
351
	for (let i = 0; i < ae.GetUplMsgCount(); i++) {
352
		const row = tbl.insertRow(-1);
353
		let cell;
354
		cell = row.insertCell(-1); cell.textContent = new Date(ae.GetUplMsgTime(i) * 1000).toISOString().slice(0, 10);
355
356
		cell = row.insertCell(-1); cell.textContent = ae.GetUplMsgTitle(i);
357
		cell.onclick = function() {displayFile(this.parentElement.rowIndex - 1);};
358
359
		cell = row.insertCell(-1); cell.textContent = ""; // Format
360
		cell = row.insertCell(-1); cell.textContent = ""; // Size
361
362
		cell = row.insertCell(-1); cell.innerHTML = "<button data-msgid=\"" + ae.GetUplMsgIdHex(i) + "\" type=\"button\">X</button>";
363
		cell.children[0].onclick = function() {
364
			const tr = this.parentElement.parentElement;
365
			ae.Message_Delete(this.getAttribute("data-msgid"), function(success) {
366
				if (success) tr.remove();
367
			});
368
		};
369
	}
370
}
371
372
function updateAddressCounts() {
373
	document.getElementById("limit_normal").textContent = (ae.GetAddressCountNormal() + "/" + ae.GetAddressLimitNormal(ae.GetUserLevel())).padStart(ae.GetAddressLimitNormal(ae.GetUserLevel()) > 9 ? 5 : 1);
374
	document.getElementById("limit_shield").textContent = (ae.GetAddressCountShield() + "/" + ae.GetAddressLimitShield(ae.GetUserLevel())).padStart(ae.GetAddressLimitShield(ae.GetUserLevel()) > 9 ? 5 : 1);
375
	document.getElementById("limit_total").textContent = ((ae.GetAddressCountNormal() + ae.GetAddressCountShield()) + "/" + ae.GetAddrPerUser()).padStart(5);
376
}
377
378
function adjustLevel(pubkey, level, c) {
379
	const fs = document.getElementById("fs_accs");
380
	fs.disabled = true;
381
382
	ae.Account_Update(pubkey, level, function(success) {
383
		fs.disabled = false;
384
385
		if (success) {
386
			c[4].textContent = level;
387
			c[5].children[0].disabled = (level === 3);
388
			c[6].children[0].disabled = (level === 0);
389
		}
390
	});
391
}
392
393
function addAccountToTable(i) {
394
	const tblAccs = document.getElementById("tbd_accs");
395
	const row = tblAccs.insertRow(-1);
396
	let cell;
397
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserPkHex(i);
398
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserSpace(i);
399
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserNAddr(i);
400
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserSAddr(i);
401
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserLevel(i);
402
403
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">+</button>";
404
	cell.children[0].onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(c[0].textContent, parseInt(c[4].textContent) + 1, c);};
405
	cell.children[0].disabled = (ae.Admin_GetUserLevel(i) === 3);
406
407
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">&minus;</button>";
408
	cell.children[0].onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(c[0].textContent, parseInt(c[4].textContent) - 1, c);};
409
	cell.children[0].disabled = (ae.Admin_GetUserLevel(i) === 0);
410
411
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">X</button>";
412
	cell.children[0].onclick = function() {
413
		const tr = this.parentElement.parentElement;
414
		ae.Account_Delete(tr.cells[0].textContent, function(success) {
415
			if (success) tr.remove();
416
		});
417
	};
418
}
419
420
function reloadAccount() {
421
	// Limits
422
	const tblLimits = document.getElementById("tbl_limits");
423
	for (let i = 0; i < 4; i++) {
424
		tblLimits.rows[i].cells[1].children[0].value = ae.GetStorageLimit(i) + 1;
425
		tblLimits.rows[i].cells[2].children[0].value = ae.GetAddressLimitNormal(i);
426
		tblLimits.rows[i].cells[3].children[0].value = ae.GetAddressLimitShield(i);
427
	}
428
429
	// Accounts
430
	const tblAccs = document.getElementById("tbd_accs");
431
432
	// All: Our account
433
	const row = tblAccs.insertRow(-1);
434
	let cell;
435
	cell = row.insertCell(-1); cell.textContent = ae.GetUserPkHex();
436
	cell = row.insertCell(-1); cell.textContent = Math.round(ae.GetTotalMsgBytes() / 1024);
437
	cell = row.insertCell(-1); cell.textContent = ae.GetAddressCountNormal();
438
	cell = row.insertCell(-1); cell.textContent = ae.GetAddressCountShield();
439
	cell = row.insertCell(-1); cell.textContent = ae.GetUserLevel();
440
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\" disabled=\"disabled\">+</button>";
441
442
	cell = row.insertCell(-1); cell.innerHTML = "<button id=\"btn_downme\" type=\"button\" autocomplete=\"off\" disabled=\"disabled\">&minus;</button>";
443
	cell.children[0].onclick = function() {
444
		const newLevel = parseInt(row.cells[4].textContent) - 1;
445
		ae.Account_Update(ae.GetUserPkHex(), newLevel, function(success) {
446
			if (success) row.cells[4].textContent = newLevel;
447
		});
448
	};
449
450
	cell = row.insertCell(-1); cell.innerHTML = "<button id=\"btn_killme\" type=\"button\" autocomplete=\"off\" disabled=\"disabled\">X</button>";
451
	cell.children[0].onclick = function() {
452
		ae.Account_Delete(ae.GetUserPkHex(), function(success) {
453
			if (success) row.remove();
454
		});
455
	};
456
457
	// Admin: Other accounts
458
	if (ae.IsUserAdmin()) {
459
		for (let i = 0; i < ae.Admin_GetUserCount(); i++) {
460
			addAccountToTable(i);
461
		}
462
	}
463
464
	document.getElementById("txt_reg").disabled = !ae.IsUserAdmin();
465
	document.getElementById("btn_reg").disabled = !ae.IsUserAdmin();
466
467
	// Contacts
468
	for (let i = 0; i < ae.GetContactCount(); i++) {
469
		addContact(
470
			ae.GetContactMail(i),
471
			ae.GetContactName(i),
472
			ae.GetContactNote(i)
473
		);
474
	}
475
476
	// Addresses
477
	for (let i = 0; i < ae.GetAddressCount(); i++) {
478
		addAddress(i);
479
	}
480
481
	updateAddressCounts();
482
}
483
484 View Code Duplication
function deleteAddress(addr) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
485
	let btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
486
	for (let i = 0; i < btns.length; i++) btns[i].disabled = true;
487
488
	let addressToDelete = -1;
489
490
	for (let i = 0; i < ae.GetAddressCount(); i++) {
491
		if (addr === ae.GetAddress(i)) {
492
			addressToDelete = i;
493
			break;
494
		}
495
	}
496
497
	if (addressToDelete === -1) return;
498
499
	ae.Address_Delete(addressToDelete, function(success) {
500
		if (success) {
501
			document.getElementById("tbl_addrs").deleteRow(addressToDelete);
502
			document.getElementById("write_from").remove(addressToDelete);
503
			updateAddressCounts();
504
505
			if (ae.GetAddressCountNormal() < ae.GetAddressLimitNormal(ae.GetUserLevel())) document.getElementById("btn_address_create_normal").disabled = false;
506
			if (ae.GetAddressCountShield() < ae.GetAddressLimitShield(ae.GetUserLevel())) document.getElementById("btn_address_create_shield").disabled = false;
507
508
			ae.Private_Update(function(success2) {
509
				if (!success2) console.log("Failed to update the Private field");
510
511
				btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
512
				for (let i = 0; i < btns.length; i++) btns[i].disabled = false;
513
			});
514
		} else {
515
			console.log("Failed to delete address");
516
517
			btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
518
			for (let i = 0; i < btns.length; i++) btns[i].disabled = false;
519
		}
520
	});
521
}
522
523 View Code Duplication
function shieldMix(addr) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
524
	let newAddr = "";
525
526
	for (let i = 0; i < 16; i++) {
527
		switch (addr.charAt(i)) {
528
			case '1':
529
				newAddr += "1iIlL".charAt(Math.floor(Math.random() * 5));
530
				break;
531
			case '0':
532
				newAddr += "0oO".charAt(Math.floor(Math.random() * 3));
533
				break;
534
			case 'w':
535
				newAddr += "VvWw".charAt(Math.floor(Math.random() * 4));
536
				break;
537
			default:
538
				newAddr += (Math.random() > 0.5) ? addr.charAt(i) : addr.charAt(i).toUpperCase();
539
		}
540
	}
541
542
	return newAddr;
543
}
544
545
function addAddress(num) {
546
	const addrTable = document.getElementById("tbl_addrs");
547
	const row = addrTable.insertRow(-1);
548
	const cellAddr = row.insertCell(-1);
549
	const cellChk1 = row.insertCell(-1);
550
	const cellChk2 = row.insertCell(-1);
551
	const cellChk3 = row.insertCell(-1);
552
	const cellBtnD = row.insertCell(-1);
553
554
	cellAddr.textContent = ae.GetAddress(num);
555
	cellAddr.onclick = function() {
556
		if (cellAddr.textContent.length === 16)
557
			navigator.clipboard.writeText(shieldMix(cellAddr.textContent) + "@" + ae.GetDomainEml());
1 ignored issue
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
558
		else
559
			navigator.clipboard.writeText(cellAddr.textContent + "@" + ae.GetDomainEml());
560
	};
561
562
	cellChk1.innerHTML = ae.GetAddressAccExt(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
563
	cellChk2.innerHTML = ae.GetAddressAccInt(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
564
	cellChk3.innerHTML = ae.GetAddressUse_Gk(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
565
566
	cellBtnD.innerHTML = "<button type=\"button\">X</button>";
567
	cellBtnD.onclick = function() {deleteAddress(cellAddr.textContent);};
568
569
	const opt = document.createElement("option");
570
	opt.value = cellAddr.textContent;
571
	opt.textContent = cellAddr.textContent + "@" + ae.GetDomainEml();
572
	document.getElementById("write_from").appendChild(opt);
573
}
574
575
document.getElementById("btn_dele").onclick = function() {
576
	this.blur();
577
578
	if (tab === TAB_WRITE) {
579
		tabs[tab].cur = 0;
580
		updateTab();
581
582
		document.getElementById("write_recv").value = "";
583
		document.getElementById("write_subj").value = "";
584
		document.getElementById("write_body").value = "";
585
586
		document.getElementById("write_recv").focus();
587
	}
588
};
589
590
document.getElementById("btn_updt").onclick = function() {
591
	const btn = this;
592
	btn.disabled = true;
593
	btn.blur();
594
595
	if (tab === TAB_INBOX) {
596
		document.getElementById("tbl_inbox").style.opacity = 0.5;
597
598
		ae.Message_Browse(true, function(successBrowse) {
599
			document.getElementById("tbl_inbox").style.opacity = 1;
600
601
			if (successBrowse) {
602
				addMessages();
603
				addUploads();
604
				btn.disabled = false;
605
			} else {
606
				console.log("Failed to refresh");
607
				btn.disabled = false;
608
			}
609
		});
610
	}
611
};
612
613
function addContact(mail, name, note) {
614
	const tbl = document.getElementById("tbl_ctact");
615
	const row = tbl.insertRow(-1);
616
	const cellMail = row.insertCell(-1);
617
	const cellName = row.insertCell(-1);
618
	const cellNote = row.insertCell(-1);
619
	const cellBtnD = row.insertCell(-1);
620
621
	cellMail.textContent = mail;
622
	cellName.textContent = name;
623
	cellNote.textContent = note;
624
	cellBtnD.innerHTML = "<button type=\"button\">X</button>";
625
626
	cellMail.contentEditable = true;
627
	cellName.contentEditable = true;
628
	cellNote.contentEditable = true;
629
630
	cellBtnD.onclick = function() {row.remove();};
631
}
632
633
document.getElementById("btn_newcontact").onclick = function() {
634
	addContact("", "", "");
635
};
636
637
document.getElementById("btn_savecontacts").onclick = function() {
638
	while (ae.GetContactCount() > 0) {
639
		ae.DeleteContact(0);
640
	}
641
642
	for (const row of document.getElementById("tbl_ctact").rows) {
643
		ae.AddContact(row.cells[0].textContent, row.cells[1].textContent, row.cells[2].textContent);
644
	}
645
646
	const btn = this;
647
	btn.disabled = true;
648
649
	ae.Private_Update(function(success) {
650
		btn.disabled = false;
651
652
		if (!success) {
653
			console.log("Failed contacts update");
654
		}
655
	});
656
};
657
658
function updateTab() {
659
	switch (tab) {
660
		case TAB_INBOX:
661
			addMessages();
662
		break;
663
664
		case TAB_WRITE:
665
			switch (tabs[tab].cur) {
666
				case 0: // Write
667
					document.getElementById("div_write_1").hidden = false;
668
					document.getElementById("div_write_2").hidden = true;
669
					document.getElementById("write_body").focus();
670
				break;
671
672
				case 1: // Verify
673
					ae.Address_Lookup(document.getElementById("write_recv").value, function(pk) {
674
						if (pk) {
675
							document.getElementById("div_write_1").hidden = true;
676
							document.getElementById("div_write_2").hidden = false;
677
678
							document.getElementById("write2_from").textContent = document.getElementById("write_from").value + "@" + ae.GetDomainEml();
679
							document.getElementById("write2_recv").textContent = document.getElementById("write_recv").value;
680
							document.getElementById("write2_pkey").textContent = sodium.to_hex(pk);
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
681
682
							document.getElementById("write2_subj").textContent = document.getElementById("write_subj").value;
683
							document.getElementById("write2_rply").textContent = document.getElementById("write_rply").textContent;
684
							document.getElementById("write2_body").textContent = document.getElementById("write_body").value;
685
						} else {
686
							console.log("Failed lookup");
687
						}
688
					});
689
				break;
690
691
				case 2: // Send
692
					ae.Message_Create(
693
						document.getElementById("write_subj").value,
694
						document.getElementById("write_body").value,
695
						document.getElementById("write_from").value,
696
						document.getElementById("write_recv").value,
697
						document.getElementById("write_rply").textContent,
698
						(document.getElementById("write2_recv").textContent.indexOf("@") > 0) ? null : sodium.from_hex(document.getElementById("write2_pkey").textContent),
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
699
						function(success) {
700
							if (success) {
701
								console.log("Sent ok");
702
							} else {
703
								console.log("Failed sending");
704
							}
705
						}
706
					);
707
				break;
708
			}
709
		break;
710
711
		case TAB_NOTES:
712
			for (let i = 0; i <= tabs[tab].max; i++) {
713
				document.getElementById("div_notes").children[i].hidden = (i !== tabs[tab].cur);
714
			}
715
		break;
716
717
		case TAB_TOOLS:
718
			for (let i = 0; i <= tabs[tab].max; i++) {
719
				document.getElementById("div_tools").children[i].hidden = (i !== tabs[tab].cur);
720
			}
721
		break;
722
	}
723
724
	document.getElementById("btn_left").disabled = (tabs[tab].cur === 0);
725
	document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
726
}
727
728
document.getElementById("btn_left").onclick = function() {
729
	tabs[tab].cur--;
730
	if (tabs[tab].cur === 0) this.disabled = true;
731
	if (tabs[tab].cur < tabs[tab].max) document.getElementById("btn_rght").disabled = false;
732
	updateTab();
733
	this.blur();
734
};
735
736
document.getElementById("btn_rght").onclick = function() {
737
	tabs[tab].cur++;
738
	if (tabs[tab].cur === tabs[tab].max) this.disabled = true;
739
	document.getElementById("btn_left").disabled = false;
740
	updateTab();
741
	this.blur();
742
};
743
744
const buttons = document.querySelector("#main1 > .top").getElementsByTagName("button");
745
for (let i = 0; i < buttons.length; i++) {
746
	buttons[i].onclick = function() {
747
		tab = i;
748
749
		for (let j = 0; j < buttons.length; j++) {
750
			document.querySelector("#main1 > .mid").children[j].hidden = (tab !== j);
751
			buttons[j].disabled = (tab === j);
752
		}
753
754
		document.getElementById("btn_left").disabled = (tabs[tab].cur === 0);
0 ignored issues
show
Bug introduced by
The variable tab is changed as part of the for loop for example by i on line 747. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
755
		document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
756
		document.getElementById("btn_dele").disabled = !tabs[tab].btnDele;
757
		document.getElementById("btn_updt").disabled = !tabs[tab].btnUpdt;
758
	};
759
}
760
761
function addressCreate(addr) {
762
	const btnN = document.getElementById("btn_address_create_normal");
763
	const btnS = document.getElementById("btn_address_create_shield");
764
	btnN.disabled = true;
765
	btnS.disabled = true;
766
767
	ae.Address_Create(addr, function(success1) {
768
		if (success1) {
769
			ae.Private_Update(function(success2) {
770
				addAddress(ae.GetAddressCount() - 1);
771
				if (addr !== "SHIELD") document.getElementById("txt_address_create_normal").value = "";
772
				updateAddressCounts();
773
774
				if (!success2) console.log("Failed to update the Private field");
775
776
				if (ae.GetAddressCountNormal() < ae.GetAddressLimitNormal(ae.GetUserLevel())) btnN.disabled = false;
777
				if (ae.GetAddressCountShield() < ae.GetAddressLimitShield(ae.GetUserLevel())) btnS.disabled = false;
778
			});
779
		} else {
780
			console.log("Failed to add address");
781
782
			if (ae.GetAddressCountNormal() < ae.GetAddressLimitNormal(ae.GetUserLevel())) btnN.disabled = false;
783
			if (ae.GetAddressCountShield() < ae.GetAddressLimitShield(ae.GetUserLevel())) btnS.disabled = false;
784
		}
785
	});
786
}
787
788
document.getElementById("btn_address_create_normal").onclick = function() {
789
	if (ae.GetAddressCountNormal() >= ae.GetAddressLimitNormal(ae.GetUserLevel())) return;
790
791
	const txtNewAddr = document.getElementById("txt_address_create_normal");
792
	if (!txtNewAddr.reportValidity()) return;
793
794
	addressCreate(txtNewAddr.value);
795
};
796
797
document.getElementById("btn_address_create_shield").onclick = function() {
798
	if (ae.GetAddressCountShield() >= ae.GetAddressLimitShield(ae.GetUserLevel())) return;
799
800
	addressCreate("SHIELD");
801
};
802
803
document.getElementById("btn_reg").onclick = function() {
804
	const btn = document.getElementById("btn_reg");
805
	const txt = document.getElementById("txt_reg");
806
	if (!txt.reportValidity()) return;
807
	btn.disabled = true;
808
809
	ae.Account_Create(txt.value, function(success) {
810
		if (success) {
811
			addAccountToTable(ae.Admin_GetUserCount() - 1);
812
			txt.value = "";
813
		}
814
815
		btn.disabled = false;
816
	});
817
};
818
819
document.getElementById("chk_downme").onclick = function() {document.getElementById("btn_downme").disabled = !this.checked;};
820
document.getElementById("chk_killme").onclick = function() {document.getElementById("btn_killme").disabled = !this.checked;};
821
822
document.getElementById("btn_notepad_saveupl").onclick = function() {
823
	const np = document.getElementById("txt_notepad");
824
	np.disabled = true;
825
826
	let fname = prompt("Save as...", "Untitled");
0 ignored issues
show
Debugging Code Best Practice introduced by
The prompt UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
827
	if (!fname.endsWith(".txt")) fname += ".txt";
828
829
	ae.Message_Upload(fname, np.value, function(success) {
830
		if (success) {
831
			np.value = "";
832
			addUploads();
833
		}
834
835
		console.log("Failed to add text");
836
		np.disabled = false;
837
	});
838
};
839
840
document.getElementById("btn_upload").onclick = function() {
841
	const btn = this;
842
	const fileSelector = document.createElement("input");
843
	fileSelector.type = "file";
844
	fileSelector.click();
845
846
	fileSelector.onchange = function() {
847
		btn.disabled = true;
848
849
		const reader = new FileReader();
1 ignored issue
show
Bug introduced by
The variable FileReader seems to be never declared. If this is a global, consider adding a /** global: FileReader */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
850
		reader.onload = function() {
851
			ae.Message_Upload(fileSelector.files[0].name, new Uint8Array(reader.result), function(success) {
852
				if (success) {
853
					addUploads();
854
				} else {
855
					console.log("Failed upload");
856
				}
857
858
				btn.disabled = false;
859
			});
860
		};
861
862
		reader.readAsArrayBuffer(fileSelector.files[0]);
863
	};
864
};
865
866
document.getElementById("txt_skey").onkeyup = function(event) {
867
	if (event.key === "Enter") {
868
		event.preventDefault();
869
		document.getElementById("btn_enter").click();
870
	}
871
};
872
873
document.getElementById("btn_enter").onclick = function() {
874
	const txtSkey = document.getElementById("txt_skey");
875
	if (!txtSkey.reportValidity()) return;
876
877
	const btn = this;
878
	btn.disabled = true;
879
	document.getElementById("txt_skey").style.background = "#233";
880
881
	ae.SetKeys(txtSkey.value, function(successSetKeys) {
882
		if (successSetKeys) {
883
			ae.Account_Browse(0, function(successBrowse) {
884
				if (successBrowse) {
885
					txtSkey.value = "";
886
887
					reloadAccount();
888
					document.getElementById("div_begin").hidden = true;
889
					document.getElementById("div_main").style.display = "grid";
890
891
					document.getElementById("btn_updt").click();
892
				} else {
893
					console.log("Failed to enter");
894
					btn.disabled = false;
895
					document.getElementById("txt_skey").style.background = "#466";
896
					txtSkey.focus();
897
				}
898
			});
899
		} else {
900
			console.log("Invalid format for key");
901
			btn.disabled = false;
902
			document.getElementById("txt_skey").style.background = "#466";
903
			txtSkey.focus();
904
		}
905
	});
906
};
907
908
});
909